﻿
/*******************************************************************************************
// ©2009 Microsoft Corporation.  This code is provided under the Microsoft Public License.
*******************************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Rtc.Collaboration;
using System.Net;
using ApplicationProvisioning;
using Microsoft.Rtc.Signaling;

namespace UCMACellularWS
{
    public class PlatformManager
    {
        /// <summary>
        /// Method to find a certificate in the local machine’s store where the Subject Name matches the fully qualified domain name (FQDN) of the local machine.
        /// We will use this certificate to establish a TLS session with the OCS server.
        /// </summary>
        /// <returns>The certificate instance.</returns>
        private static X509Certificate2 GetLocalCertificate()
        {
            //Get a handle to the local machine's certificate store
            X509Store store = new X509Store(StoreLocation.LocalMachine);
            //Open the store
            store.Open(OpenFlags.ReadOnly);
            //Get a handle to a collection of the certificates installed on the machine
            X509Certificate2Collection certificates = store.Certificates;
            //Loop through the certificates looking for one 
            //where the SubjectName matches hte FQDN of the
            //Local Machine
            foreach (X509Certificate2 certificate in certificates)
            {
                if (certificate.SubjectName.Name.Contains
                    (Dns.GetHostEntry("localhost").HostName)
                    && certificate.HasPrivateKey)
                {
                    //Return the certificate that matches
                    return certificate;
                }
            }
            //If not certs match, return null
            return null;
        }

        /// <summary>
        /// Retrieves Collaboration platform settings using App Provisioning tool
        /// </summary>
        /// <returns></returns>
        private static ServerPlatformSettings GetPlatformSettings()
        {
            //TODO: Move UCMA platform logic (subscription, startup of service, etc into new class called PlatformManager
            string appUserAgent = PubSub.Config.ApplicationUserAgent;

            // Use the ApplicationProvisioning classes to get the platform settings.
            TrustedApplicationPool trustedAppPool = TrustedApplicationPool.GetApplicationPoolForLocalMachine(appUserAgent);

            if (trustedAppPool == null)
                throw new ArgumentNullException("GetApplicationPoolForLocalMachine()", "Application Pool not found");

            TrustedService trustedService = trustedAppPool.GetTrustedServiceForLocalMachine();

            // Make sure a trusted server entry exists
            if (trustedService == null)
            {
                throw new ArgumentNullException("GetTrustedServiceForLocalMachine()", "Trusted Service Entry not found");
            }

            // Make sure atleast one contact for the trusted server entry exists
            if (trustedAppPool.Contacts.Count == 0)
            {
                throw new ArgumentNullException("Contact Object not found for trusted service");
            }

            return
                new ServerPlatformSettings(
                    appUserAgent,
                    trustedService.Fqdn,
                    trustedService.Port,
                    trustedService.Gruu,
                    GetLocalCertificate()
                );
        }

        /// <summary>
        /// Setup Collaboration platform and App End point to communicate with OCS server
        /// </summary>
        public static void PreparePlatformAndEndpoint()
        {
            try
            {
                //Collaboration platform initialization
                ServerPlatformSettings platformSettings = GetPlatformSettings();

                PubSub.CollabPlatform = new CollaborationPlatform(platformSettings);

                PubSub.CollabPlatform.EndStartup(PubSub.CollabPlatform.BeginStartup(null, null));

                //Create User Endpoint based on sip address provided
                //Create the UserEndpointSettings 
                UserEndpointSettings settings = new UserEndpointSettings(PubSub.Config.BotUri,
                                                                        PubSub.Config.OcsServerFqdn,
                                                                        PubSub.Config.OcsServerTlsPort);
                PubSub.BotEndPoint = new UserEndpoint(PubSub.CollabPlatform, settings);

                //synchronously call the establish method
                PubSub.BotEndPoint.EndEstablish(PubSub.BotEndPoint.BeginEstablish(null, null));

            }
            catch (ConnectionFailureException connFailEx)
            {
                // ConnectionFailureException will be thrown when the platform cannot connect.
                PubSub.Logger.Log(connFailEx);
            }
            catch (InvalidOperationException iOpEx)
            {
                // InvalidOperationException will be thrown when the endpoint is not in a valid state to connect. To connect, the platform must be started and the Endpoint Idle.
                PubSub.Logger.Log(iOpEx);
            }
            catch (RegisterException regEx)
            {
                // RegisterException will be thrown when the endpoint cannot be registered (usually due to bad credentials).
                PubSub.Logger.Log(regEx);
            }
        }
    }
}
